Skip to content

refactor(ram): batch ValEvaluation and ValFinal into RamValCheck#1203

Merged
moodlezoup merged 11 commits intoa16z:mainfrom
quangvdao:quang/fuse-val-evaluation
Feb 17, 2026
Merged

refactor(ram): batch ValEvaluation and ValFinal into RamValCheck#1203
moodlezoup merged 11 commits intoa16z:mainfrom
quangvdao:quang/fuse-val-evaluation

Conversation

@quangvdao
Copy link
Contributor

@quangvdao quangvdao commented Jan 14, 2026

Summary

This PR’s main contribution is a Stage 4 RAM value refactor: it replaces two separate RAM value sumchecks on main (ValEvaluation and ValFinal) with a single batched sumcheck instance: RamValCheck.

To make that batching clean (and to enable further simplifications), Stage 2 is also refactored so RamRafEvaluation and RamOutputCheck consume transcript challenges in the exact same global rounds that RamReadWriteChecking binds RAM address variables, independent of ReadWriteConfig.

Stage 4: RamValCheck batches ValEvaluation + ValFinal

What changes vs main:

  • main had two Stage 4 sumchecks (ValEvaluation, ValFinal), each with its own cached openings.
  • This PR replaces them with one log(T)-round sumcheck instance in jolt-core/src/zkvm/ram/val_check.rs.

Batched identity (one shared r_address)
At the aligned RAM address point r_address and RW’s cycle point r_cycle, we check:

  • (1) Val(r_address, r_cycle) - Val_init(r_address) = Σ_j inc(j) · wa(r_address, j) · LT(j, r_cycle)
  • (2) Val_final(r_address) - Val_init(r_address) = Σ_j inc(j) · wa(r_address, j)

and batch them with a transcript challenge γ (domain sep label ram_val_check_gamma):

  • (1) + γ·(2) = Σ_j inc(j) · wa(r_address, j) · ( LT(j, r_cycle) + γ )

Where does Val_init(r_address) come from now?

  • It is not part of the RamOutputCheck identity.
  • RamValCheck derives it from public initial RAM (plus advice contributions on the verifier path), rather than plumbing it as an OutputCheck-cached virtual opening.

Openings / IDs

  • SumcheckId::RamValEvaluation and SumcheckId::RamValFinalEvaluation are removed; Stage 4 uses only SumcheckId::RamValCheck.
  • RamValCheck caches:
    • VirtualPolynomial::RamRa at (r_address || r_cycle′) under SumcheckId::RamValCheck
    • CommittedPolynomial::RamInc at r_cycle′ under SumcheckId::RamValCheck

This eliminates the need to maintain two separate “val” opening IDs/points downstream.

Stage 2: align address rounds (enables the Stage 4 simplification)

To ensure a single shared r_address across RAM protocols (regardless of ReadWriteConfig):

  • RamRafEvaluation (jolt-core/src/zkvm/ram/raf_evaluation.rs)

    • Inflates num_rounds() to match RW’s address-binding schedule and uses internal dummy rounds (constant univariates + ignore challenges) during RW Phase 3’s cycle region.
    • Renormalizes its input_claim() by 2^{(#dummy rounds)} so the batched transcript remains consistent.
    • normalize_opening_point() extracts only the address challenges (skipping dummy rounds), so its cached r_address matches RW’s.
  • RamOutputCheck (jolt-core/src/zkvm/ram/output_check.rs)

    • Mirrors the same inflated-round schedule + dummy rounds + address-challenge extraction, ensuring its cached r_address matches RW’s.
    • Only caches the opening needed downstream (VirtualPolynomial::RamValFinal); it does not cache or bind Val_init.

Stage 5: RA claim reduction becomes cycle-only (log_T rounds)

With r_address already aligned and fixed, RamRaClaimReduction no longer needs to reduce over address variables:

  • jolt-core/src/zkvm/claim_reductions/ram_ra.rs: num_rounds() == log_T.
  • Still caches a full opening point (r_address || r_cycle_reduced) under SumcheckId::RamRaClaimReduction so ram/ra_virtual.rs can keep splitting at log_K.

Advice claim reduction: single opening only

  • jolt-core/src/zkvm/claim_reductions/advice.rs now always uses a single advice opening derived from SumcheckId::RamValCheck.
  • Removes the entire “optional second opening” machinery.

Files changed (high signal)

  • jolt-core/src/zkvm/ram/val_check.rs (new Stage 4 batched sumcheck)
  • jolt-core/src/zkvm/ram/raf_evaluation.rs (alignment + dummy rounds + input-claim renormalization)
  • jolt-core/src/zkvm/ram/output_check.rs (alignment + dummy rounds; drop unused Val_init plumbing)
  • jolt-core/src/zkvm/claim_reductions/ram_ra.rs (cycle-only reduction)
  • jolt-core/src/zkvm/claim_reductions/advice.rs (single opening only)
  • jolt-core/src/poly/opening_proof.rs (SumcheckId cleanup: RamValCheck)
  • jolt-core/src/zkvm/{prover,verifier}.rs (wiring + transcript label ram_val_check_gamma)

Testing

  • cargo test -p jolt-core --lib --no-run
  • Added/updated unit tests around Stage 2 address alignment and RA reduction opening-point shape.

Review guidance

  • Start with jolt-core/src/zkvm/ram/val_check.rs docstring + cache_openings logic (this is the core Stage 4 batching).
  • Then review Stage 2 alignment mechanics in raf_evaluation.rs / output_check.rs (num_rounds, round_offset, dummy rounds, and normalize_opening_point).
  • Finally check that all downstream consumers now consistently use SumcheckId::RamValCheck (advice + increments + RA reduction).

@quangvdao
Copy link
Contributor Author

Pushed follow-up commit removing the legacy separate RAM val sumchecks now that Stage 4 uses . Commit: 4b237af.

@quangvdao
Copy link
Contributor Author

Follow-up: removed the legacy separate RAM val_evaluation / val_final sumcheck modules now that Stage 4 uses the fused sumcheck in val_fused.rs.

Commit: 4b237af

@quangvdao quangvdao changed the title DRAFT: fuse RAM ValEvaluation + ValFinal sumchecks (stage4) fuse RAM ValEvaluation + ValFinal sumchecks (stage4) Jan 27, 2026
@quangvdao quangvdao marked this pull request as ready for review January 27, 2026 19:43
quangvdao and others added 3 commits January 27, 2026 11:46
Stage 4 verifier referenced `ram::gen_ram_initial_memory_state` without importing the module.
Use the fully qualified `crate::zkvm::ram::...` path so the workspace builds in CI.
Align Stage 2 RAM sumchecks with RW address-binding rounds via internal dummy rounds, and simplify downstream value/RA reductions by unifying on a single aligned r_address.

Co-authored-by: Cursor <cursoragent@cursor.com>
@quangvdao quangvdao changed the title fuse RAM ValEvaluation + ValFinal sumchecks (stage4) refactor(zkvm): align RAM rounds and simplify RamValCheck Feb 16, 2026
@quangvdao quangvdao changed the title refactor(zkvm): align RAM rounds and simplify RamValCheck refactor(ram): batch ValEvaluation and ValFinal into RamValCheck Feb 16, 2026
quangvdao and others added 4 commits February 15, 2026 19:43
OutputCheck no longer needs to cache RamValInit now that Stage 4 is consolidated under RamValCheck. Avoid emitting an unused virtual opening (which trips release test assertions that all cached virtual openings are consumed).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
OutputCheck only checks IO consistency via Val_final - Val_io, so it does not need to bind or cache Val_init. After consolidating Stage 4 into RamValCheck, Val_init is derived from public initial RAM (plus advice) rather than being plumbed through OutputCheck openings.

Co-authored-by: Cursor <cursoragent@cursor.com>
@moodlezoup moodlezoup merged commit 432d1c3 into a16z:main Feb 17, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants